<!--
  通用表单组件 (CommonForm.vue)
  
  【组件功能】
  这是一个基于 Element Plus 的通用表单组件，支持多种表单控件类型，通过配置化的方式快速构建表单。
  
  【主要特性】
  1. 支持多种表单控件：输入框、文本域、数字输入框、选择器、级联选择器、日期选择器、时间选择器、
     单选框、复选框、开关、滑块、评分、颜色选择器、上传组件等
  2. 响应式布局：支持栅格系统，可配置不同屏幕尺寸下的显示效果
  3. 表单验证：支持 Element Plus 的表单验证规则
  4. 事件处理：提供统一的事件处理机制
  5. 自定义插槽：支持通过插槽扩展自定义控件
  
  【配置项说明】
  config: 表单配置数组，每个元素包含以下属性：
    - type: 控件类型，支持 'input'|'textarea'|'number'|'select'|'cascader'|'date'|'time'|'radio'|'radio-button'|'checkbox'|'checkbox-button'|'switch'|'slider'|'rate'|'color'|'upload'|'slot'
    - prop: 字段名，用于数据绑定和验证
    - label: 标签文本
    - placeholder: 占位符文本
    - required: 是否必填
    - rules: 验证规则（会与全局 rules 合并）
    - disabled: 是否禁用
    - span/xs/sm/md/lg/xl: 栅格布局配置
  
  【控件类型详解】
  1. input: 输入框
     - inputType: 输入类型 (text|password|email|url|tel|number)
     - maxlength: 最大长度
     - showWordLimit: 是否显示字数统计
     - clearable: 是否可清空
     - readonly: 是否只读
  
  2. textarea: 文本域
     - rows: 行数
     - maxlength: 最大长度
     - showWordLimit: 是否显示字数统计
  
  3. number: 数字输入框
     - min/max: 最小/最大值
     - step: 步长
     - precision: 精度
     - controls: 是否显示控制按钮
  
  4. select: 选择器
     - multiple: 是否多选
     - collapseTags: 是否折叠标签
     - filterable: 是否可搜索
     - remote: 是否远程搜索
     - options: 选项数组 [{label, value, disabled}]
  
  5. cascader: 级联选择器
     - options: 级联数据
     - props: 配置选项
     - filterable: 是否可搜索
     - showAllLevels: 是否显示完整路径
  
  6. date: 日期选择器
     - dateType: 日期类型 (date|datetime|daterange|datetimerange)
     - format: 显示格式
     - valueFormat: 值格式
     - rangeSeparator: 范围分隔符
  
  7. time: 时间选择器
     - format: 显示格式
     - valueFormat: 值格式
     - isRange: 是否范围选择
  
  8. radio/radio-button: 单选框/单选框按钮
     - options: 选项数组
  
  9. checkbox/checkbox-button: 复选框/复选框按钮
     - options: 选项数组
  
  10. switch: 开关
      - activeText/inactiveText: 激活/未激活文本
      - activeValue/inactiveValue: 激活/未激活值
  
  11. slider: 滑块
      - min/max: 最小/最大值
      - step: 步长
      - range: 是否范围选择
      - marks: 标记点
  
  12. rate: 评分
      - max: 最大值
      - colors: 颜色数组
      - showScore: 是否显示分数
  
  13. color: 颜色选择器
      - showAlpha: 是否支持透明度
      - colorFormat: 颜色格式
      - predefine: 预定义颜色
  
  14. upload: 上传组件
      - action: 上传地址
      - headers: 请求头
      - data: 额外参数
      - multiple: 是否多文件
      - accept: 接受的文件类型
      - limit: 文件数量限制
      - listType: 列表类型
      - autoUpload: 是否自动上传
      - drag: 是否支持拖拽
  
  15. slot: 自定义插槽
      - slotName: 插槽名称
  
  【重复字段处理】
  1. prop 重复：后定义的会覆盖先定义的，建议确保 prop 唯一性
  2. 验证规则重复：item.rules 会与全局 rules 合并，item.rules 优先级更高
  3. 样式重复：通过 span/xs/sm/md/lg/xl 控制布局，避免重复显示
  
  【事件处理】
  - @submit: 表单提交事件，参数为表单数据对象
  - @reset: 表单重置事件
  - @cancel: 取消操作事件
  - @change: 字段值变化事件，参数为 (prop, value)
  - @input: 输入事件，参数为 (prop, value)
  - @clear: 清除事件，参数为 prop
  
  【使用示例】
  <CommonForm
    v-model="formData"
    :config="formConfig"
    :rules="formRules"
    @submit="handleSubmit"
    @reset="handleReset"
  />
  
  【注意事项】
  1. 确保 formData 对象包含所有配置的 prop 字段
  2. 验证规则支持 Element Plus 的所有验证规则
  3. 上传组件需要配置正确的 action 地址
  4. 远程搜索需要实现 remoteMethod 方法
  5. 自定义插槽需要提供对应的插槽内容
-->

<template>
  <div class="common-form">
    <el-form
      ref="formRef"
      :model="formData"
      :rules="rules"
      :label-width="labelWidth"
      :label-position="labelPosition"
      :size="size"
      :disabled="disabled"
      class="form-container"
    >
      <el-row :gutter="gutter">
        <el-col
          v-for="(item, index) in formConfig"
          :key="index"
          :span="item.span || 24"
          :xs="item.xs || 24"
          :sm="item.sm || item.span || 24"
          :md="item.md || item.span || 24"
          :lg="item.lg || item.span || 24"
          :xl="item.xl || item.span || 24"
        >
          <el-form-item
            :label="item.label"
            :prop="item.prop"
            :required="item.required"
            :rules="item.rules"
            :class="{
              'no-label': item.type === 'actions' || item.labelWidth === 0,
            }"
            :label-width="
              item.type === 'actions' ? '0px' : item.labelWidth ?? undefined
            "
          >
            <!-- 输入框 -->
            <el-input
              v-if="item.type === 'input'"
              v-model="formData[item.prop]"
              :placeholder="item.placeholder"
              :type="item.inputType || 'text'"
              :maxlength="item.maxlength"
              :show-word-limit="item.showWordLimit"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :readonly="item.readonly"
              @input="handleInput(item.prop, $event)"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 文本域 -->
            <el-input
              v-else-if="item.type === 'textarea'"
              v-model="formData[item.prop]"
              :placeholder="item.placeholder"
              :rows="item.rows || 3"
              :maxlength="item.maxlength"
              :show-word-limit="item.showWordLimit"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :readonly="item.readonly"
              type="textarea"
              @input="handleInput(item.prop, $event)"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 数字输入框 -->
            <el-input-number
              v-else-if="item.type === 'number'"
              v-model="formData[item.prop]"
              :placeholder="item.placeholder"
              :min="item.min"
              :max="item.max"
              :step="item.step || 1"
              :precision="item.precision"
              :controls="item.controls !== false"
              :disabled="item.disabled"
              :readonly="item.readonly"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 选择器 -->
            <el-select
              v-else-if="item.type === 'select'"
              v-model="formData[item.prop]"
              :placeholder="item.placeholder"
              :multiple="item.multiple"
              :collapse-tags="item.collapseTags"
              :collapse-tags-tooltip="item.collapseTagsTooltip"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :filterable="item.filterable"
              :remote="item.remote"
              :remote-method="item.remoteMethod"
              :loading="item.loading"
              :reserve-keyword="item.reserveKeyword"
              @change="handleChange(item.prop, $event)"
              @clear="handleClear(item.prop)"
            >
              <el-option
                v-for="option in item.options"
                :key="option.value"
                :label="option.label"
                :value="option.value"
                :disabled="option.disabled"
              />
            </el-select>

            <!-- 级联选择器 -->
            <el-cascader
              v-else-if="item.type === 'cascader'"
              v-model="formData[item.prop]"
              :options="item.options"
              :placeholder="item.placeholder"
              :props="item.props || {}"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :filterable="item.filterable"
              :show-all-levels="item.showAllLevels !== false"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 日期选择器 -->
            <el-date-picker
              v-else-if="item.type === 'date'"
              v-model="formData[item.prop]"
              :type="item.dateType || 'date'"
              :placeholder="item.placeholder"
              :format="item.format"
              :value-format="item.valueFormat"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :readonly="item.readonly"
              :range-separator="item.rangeSeparator || '-'"
              :start-placeholder="item.startPlaceholder"
              :end-placeholder="item.endPlaceholder"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 时间选择器 -->
            <el-time-picker
              v-else-if="item.type === 'time'"
              v-model="formData[item.prop]"
              :placeholder="item.placeholder"
              :format="item.format || 'HH:mm:ss'"
              :value-format="item.valueFormat || 'HH:mm:ss'"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :readonly="item.readonly"
              :is-range="item.isRange"
              :range-separator="item.rangeSeparator || '-'"
              :start-placeholder="item.startPlaceholder"
              :end-placeholder="item.endPlaceholder"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 单选框组 -->
            <el-radio-group
              v-else-if="item.type === 'radio'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              @change="handleChange(item.prop, $event)"
            >
              <el-radio
                v-for="option in item.options"
                :key="option.value"
                :label="option.value"
                :disabled="option.disabled"
              >
                {{ option.label }}
              </el-radio>
            </el-radio-group>

            <!-- 单选框按钮组 -->
            <el-radio-group
              v-else-if="item.type === 'radio-button'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              @change="handleChange(item.prop, $event)"
            >
              <el-radio-button
                v-for="option in item.options"
                :key="option.value"
                :label="option.value"
                :disabled="option.disabled"
              >
                {{ option.label }}
              </el-radio-button>
            </el-radio-group>

            <!-- 复选框组 -->
            <el-checkbox-group
              v-else-if="item.type === 'checkbox'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              @change="handleChange(item.prop, $event)"
            >
              <el-checkbox
                v-for="option in item.options"
                :key="option.value"
                :label="option.value"
                :disabled="option.disabled"
              >
                {{ option.label }}
              </el-checkbox>
            </el-checkbox-group>

            <!-- 复选框按钮组 -->
            <el-checkbox-group
              v-else-if="item.type === 'checkbox-button'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              @change="handleChange(item.prop, $event)"
            >
              <el-checkbox-button
                v-for="option in item.options"
                :key="option.value"
                :label="option.value"
                :disabled="option.disabled"
              >
                {{ option.label }}
              </el-checkbox-button>
            </el-checkbox-group>

            <!-- 开关 -->
            <el-switch
              v-else-if="item.type === 'switch'"
              v-model="formData[item.prop]"
              :active-text="item.activeText"
              :inactive-text="item.inactiveText"
              :active-value="
                item.activeValue !== undefined ? item.activeValue : true
              "
              :inactive-value="
                item.inactiveValue !== undefined ? item.inactiveValue : false
              "
              :disabled="item.disabled"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 滑块 -->
            <el-slider
              v-else-if="item.type === 'slider'"
              v-model="formData[item.prop]"
              :min="item.min || 0"
              :max="item.max || 100"
              :step="item.step || 1"
              :range="item.range"
              :show-tooltip="item.showTooltip !== false"
              :disabled="item.disabled"
              :marks="item.marks"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 评分 -->
            <el-rate
              v-else-if="item.type === 'rate'"
              v-model="formData[item.prop]"
              :max="item.max || 5"
              :colors="item.colors"
              :low-threshold="item.lowThreshold || 2"
              :high-threshold="item.highThreshold || 4"
              :disabled="item.disabled"
              :show-score="item.showScore"
              :texts="item.texts"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 颜色选择器 -->
            <el-color-picker
              v-else-if="item.type === 'color'"
              v-model="formData[item.prop]"
              :show-alpha="item.showAlpha"
              :color-format="item.colorFormat || 'hex'"
              :disabled="item.disabled"
              :predefine="item.predefine"
              @change="handleChange(item.prop, $event)"
            />

            <!-- 上传组件 -->
            <el-upload
              v-else-if="item.type === 'upload'"
              v-model:file-list="formData[item.prop]"
              :action="item.action"
              :headers="item.headers"
              :data="item.data"
              :name="item.name || 'file'"
              :multiple="item.multiple"
              :accept="item.accept"
              :limit="item.limit"
              :file-list="item.fileList"
              :list-type="item.listType || 'text'"
              :auto-upload="item.autoUpload !== false"
              :disabled="item.disabled"
              :drag="item.drag"
              :before-upload="item.beforeUpload"
              :on-success="item.onSuccess"
              :on-error="item.onError"
              :on-exceed="item.onExceed"
              :on-remove="item.onRemove"
            >
              <el-button v-if="item.listType !== 'picture-card'" type="primary">
                <el-icon><Upload /></el-icon>
                {{ item.buttonText || "点击上传" }}
              </el-button>
              <el-icon v-else><Plus /></el-icon>
            </el-upload>

            <!-- 自定义插槽 -->
            <slot
              v-else-if="item.type === 'slot'"
              :name="item.slotName"
              :form-data="formData"
              :item="item"
            />
            <!-- 操作按钮（作为一个表单项，随栅格响应式换行） -->
            <template v-else-if="item.type === 'actions'">
              <div :class="['actions-wrapper', item.align || actionsAlign]">
                <el-button
                  v-if="item.showSubmit ?? showSubmit"
                  type="primary"
                  :loading="submitLoading"
                  :disabled="disabled"
                  @click="handleSubmit"
                >
                  {{ item.submitText || submitText }}
                </el-button>
                <el-button
                  v-if="item.showReset ?? showReset"
                  :disabled="disabled"
                  @click="handleReset"
                >
                  {{ item.resetText || resetText }}
                </el-button>
                <el-button
                  v-if="item.showCancel ?? showCancel"
                  :disabled="disabled"
                  @click="handleCancel"
                >
                  {{ item.cancelText || cancelText }}
                </el-button>
              </div>
            </template>
            <!-- 默认输入框 -->
            <el-input
              v-else
              v-model="formData[item.prop]"
              :placeholder="item.placeholder"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              @input="handleInput(item.prop, $event)"
              @change="handleChange(item.prop, $event)"
            />
          </el-form-item>
        </el-col>
      </el-row>

      <!-- 表单按钮 -->
      <!-- <div v-if="showButtons" class="form-buttons">
        <el-button
          v-if="showSubmit"
          type="primary"
          :loading="submitLoading"
          :disabled="disabled"
          @click="handleSubmit"
        >
          {{ submitText }}
        </el-button>
        <el-button v-if="showReset" :disabled="disabled" @click="handleReset">
          {{ resetText }}
        </el-button>
        <el-button v-if="showCancel" :disabled="disabled" @click="handleCancel">
          {{ cancelText }}
        </el-button>
      </div> -->
    </el-form>
  </div>
</template>

<script setup>
import { ref, reactive, watch, computed } from "vue";
import { ElMessage } from "element-plus";
import { Upload, Plus } from "@element-plus/icons-vue";

const props = defineProps({
  actionsAlign: {
    type: String,
    default: "left", // left | center | right
  },
  // 表单配置
  config: {
    type: Array,
    default: () => [],
  },
  // 表单数据
  modelValue: {
    type: Object,
    default: () => ({}),
  },
  // 表单验证规则
  rules: {
    type: Object,
    default: () => ({}),
  },
  // 标签宽度
  labelWidth: {
    type: [String, Number],
    default: "auto",
  },
  // 标签位置
  labelPosition: {
    type: String,
    default: "right",
    validator: (value) => ["left", "right", "top"].includes(value),
  },
  // 表单尺寸
  size: {
    type: String,
    default: "default",
    validator: (value) => ["large", "default", "small"].includes(value),
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false,
  },
  // 栅格间距
  gutter: {
    type: Number,
    default: 20,
  },
  // 是否显示按钮
  showButtons: {
    type: Boolean,
    default: true,
  },
  // 是否显示提交按钮
  showSubmit: {
    type: Boolean,
    default: true,
  },
  // 是否显示重置按钮
  showReset: {
    type: Boolean,
    default: true,
  },
  // 是否显示取消按钮
  showCancel: {
    type: Boolean,
    default: false,
  },
  // 提交按钮文本
  submitText: {
    type: String,
    default: "提交",
  },
  // 重置按钮文本
  resetText: {
    type: String,
    default: "重置",
  },
  // 取消按钮文本
  cancelText: {
    type: String,
    default: "取消",
  },
  // 提交按钮加载状态
  submitLoading: {
    type: Boolean,
    default: false,
  },
});

const emit = defineEmits([
  "update:modelValue",
  "submit",
  "reset",
  "cancel",
  "change",
  "input",
  "clear",
]);

// 表单引用
const formRef = ref();

// 表单数据
const formData = reactive({});

// 监听 modelValue 变化
watch(
  () => props.modelValue,
  (newVal) => {
    Object.assign(formData, newVal);
  },
  { immediate: true, deep: true }
);

// 监听 formData 变化
watch(
  formData,
  (newVal) => {
    emit("update:modelValue", { ...newVal });
  },
  { deep: true }
);

// 表单配置
const formConfig = computed(() => props.config || []);

// 表单验证规则
const rules = computed(() => props.rules || {});

// 处理输入事件
const handleInput = (prop, value) => {
  emit("input", prop, value);
};

// 处理变化事件
const handleChange = (prop, value) => {
  emit("change", prop, value);
};

// 处理清除事件
const handleClear = (prop) => {
  emit("clear", prop);
};

// 提交表单
const handleSubmit = async () => {
  try {
    await formRef.value?.validate();
    emit("submit", { ...formData });
  } catch (error) {
    ElMessage.error("表单验证失败，请检查输入内容");
  }
};

// 重置表单
const handleReset = () => {
  formRef.value?.resetFields();
  emit("reset");
};

// 取消操作
const handleCancel = () => {
  emit("cancel");
};

// 暴露方法给父组件
defineExpose({
  formRef,
  formData,
  validate: () => formRef.value?.validate(),
  resetFields: () => formRef.value?.resetFields(),
  clearValidate: (props) => formRef.value?.clearValidate(props),
  scrollToField: (prop) => formRef.value?.scrollToField(prop),
});
</script>

<style scoped lang="less">
.common-form {
  .form-container {
    .form-buttons {
      margin-top: 20px;
      text-align: center;

      .el-button {
        margin: 0 10px;
      }
    }
  }
  :deep(.actions-wrapper) {
    display: flex;
    gap: 10px;
    &.center {
      justify-content: center;
    }
    &.right {
      justify-content: flex-end;
    }
  }
}
</style>
